home *** CD-ROM | disk | FTP | other *** search
/ Delphi Magazine Collection 2001 / Delphi Magazine Collection 20001 (2001).iso / DISKS / Issue63 / Debug / HVBordebug / BorDebugScanners.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  2000-10-02  |  16.0 KB  |  444 lines

  1. unit BorDebugScanners;
  2.  
  3. interface
  4.  
  5. uses
  6.   BorDebug,
  7.   HVBorDebug
  8.   ;
  9.  
  10. type
  11.   // TCustomBorDebugScanner is a class to help in scanning the debug info
  12.   // from start to end. To use, inherit from it and override the methods
  13.   // you are interested in.
  14.   TScanningOption = (soModule, soAlignSym, soSrcModule, soGlobalSym, soGlobalPub,
  15.     soGlobalTypes, soNames, soBrowse, soSrcModuleRanges, soSrcModuleFiles);
  16.  
  17.   TScanningOptions = set of TScanningOption;
  18.   TCustomBorDebugScanner = class(TObject)  // TObject!
  19.   private
  20.     FBorDebug: TBorDebug;
  21.     FScanningOptions: TScanningOptions;
  22.  
  23.     FCurrentSourceFileEntry: TSourceFileEntry;
  24.     FCurrentLineNumberOffsets: TLineNumberOffsets;
  25.     FCurrentSubSection: PBorDebugSubSection;
  26.     FCurrentModule: TBorDebugModule;
  27.     FCurrentSrcModule: TBorDebugSrcModule;
  28.   protected
  29.     procedure ScanSymbolTypeNode(const SubSection: TBorDebugSubSection;
  30.       SymbolInfo: TSymbolInfo; BorDebugType: TBorDebugType);
  31.     procedure ScanSymbolTypeTree(const SubSection: TBorDebugSubSection;
  32.       SymbolInfo: TSymbolInfo; TypeIndex: TTypeIndex);
  33.  
  34.     function WantType(const BorDebugType: TBorDebugType): boolean; virtual;
  35.     function WantSymbol(const Symbol: TBorDebugSymbol): boolean; virtual;
  36.     function WantFieldList(const SubSection: TBorDebugSubSection;
  37.       SymbolInfo: TSymbolInfo; const BorDebugType: TBorDebugType): boolean; virtual;
  38.     function WantTypeInfoForSymbol(SymbolInfo: TSymbolInfo; TypeIndex: TTypeIndex): boolean; virtual;
  39.     procedure StartFieldListScan(const SubSection: TBorDebugSubSection;
  40.       SymbolInfo: TSymbolInfo; BorDebugType: TBorDebugType); virtual;
  41.     procedure EndFieldListScan(const SubSection: TBorDebugSubSection;
  42.       SymbolInfo: TSymbolInfo; BorDebugType: TBorDebugType); virtual;
  43.     procedure ScanLineNumberOffset(LineNumber: TLineNumber;
  44.       LineOffset: TSegmentOffset); virtual;
  45.     procedure ScanSrcModuleSourceRange(RangeIndex: integer;
  46.       Segment: TSegmentIndex; Starts, Ends: TSegmentOffset;
  47.       LineNumberCount: TItemCount; LineNumberOffsets: TLineNumberOffsets); virtual;
  48.     procedure ScanSymbolTypeInfo(const SubSection: TBorDebugSubSection;
  49.       SymbolInfo: TSymbolInfo; TypeInfo: TTypeInfo; var KeepIt: boolean); virtual;
  50.     procedure ScanSrcModule(const SubSection: TBorDebugSubSection;
  51.       SrcModule: TBorDebugSrcModule; var KeepIt: boolean);  virtual;
  52.     procedure ScanSrcModuleRange(const SubSection: TBorDebugSubSection;
  53.       SrcModule: TBorDebugSrcModule; RangeIndex: integer;
  54.       RangeSegmentIndex: TSegmentIndex; RangeStart,
  55.       RangeEnd: TSegmentOffset);  virtual;
  56.     procedure ScanSrcModuleSource(const SubSection: TBorDebugSubSection;
  57.       SrcModule: TBorDebugSrcModule; SourceIndex: integer;
  58.       SourceOffset: TFileOffset; NameIndex: TNameIndex;
  59.       RangeCount: TItemCount; SourceFileEntry: TSourceFileEntry); virtual;
  60.     procedure ScanSymbolInfo(const SubSection: TBorDebugSubSection;
  61.       SymbolInfo: TSymbolInfo; var KeepIt: boolean);  virtual;
  62.     procedure ScanSymbols(const SubSection: TBorDebugSubSection);  virtual;
  63.     procedure ScanModule(const SubSection: TBorDebugSubSection;
  64.       Module: TBorDebugModule; var KeepIt: boolean); virtual;
  65.     procedure ScanModuleSegment(const SubSection: TBorDebugSubSection;
  66.       Module: TBorDebugModule; SegmentIndex: integer; const Segment: TModuleSegment); virtual;
  67.     procedure ScanSubSection(SubSectionIndex: integer; const SubSection: TBorDebugSubSection); virtual;
  68.     procedure ScanSubsections; virtual;
  69.     property CurrentSourceFileEntry: TSourceFileEntry read FCurrentSourceFileEntry;
  70.     property CurrentLineNumberOffsets: TLineNumberOffsets read FCurrentLineNumberOffsets;
  71.     property CurrentSubSection: PBorDebugSubSection read FCurrentSubSection;
  72.     property CurrentModule: TBorDebugModule read FCurrentModule;
  73.     property CurrentSrcModule: TBorDebugSrcModule read FCurrentSrcModule;
  74.     property ScanningOptions: TScanningOptions read FScanningOptions write FScanningOptions;
  75.   public
  76.     constructor Create(ABorDebug: TBorDebug);
  77.     procedure Scan(ScanningOptions: TScanningOptions);
  78.     property BorDebug: TBorDebug read FBorDebug write FBorDebug;
  79.   end;
  80.  
  81.   TLineNumberScannerTask = (ltMatchAddress, stMatchUnitLinenr);
  82.   TLineNumberScanner = class(TCustomBorDebugScanner)
  83.   private
  84.     FTask : TLineNumberScannerTask;
  85.     FAddress: TSegmentOffset;
  86.     FBestMatch: TSegmentOffset;
  87.     FUnitname: string;
  88.     FLinenumber: TLinenumber;
  89.     FFoundMatch: boolean;
  90.   protected
  91.     procedure ScanLineNumberOffset(LineNumber: TLineNumber; LineOffset: TSegmentOffset); override;
  92.   public
  93.     function FindUnitnameLinenumber(Address: TSegmentOffset; out Unitname: string; out Linenumber: TLinenumber): boolean;
  94.   end;
  95.  
  96. implementation
  97.  
  98. uses
  99.   SysUtils;
  100.  
  101. { Utility routines }
  102.  
  103. function SubsectionTypeToScanningOption(SubsectionType: TSubsectionType): TScanningOption;
  104. begin
  105.    case SubsectionType of
  106.       BORDEBUG_SSTMODULE      : Result := soModule;
  107.       BORDEBUG_SSTALIGNSYM    : Result := soAlignSym;
  108.       BORDEBUG_SSTSRCMODULE   : Result := soSrcModule;
  109.       BORDEBUG_SSTGLOBALSYM   : Result := soGlobalSym;
  110.       BORDEBUG_SSTGLOBALPUB   : Result := soGlobalPub;
  111.       BORDEBUG_SSTGLOBALTYPES : Result := soGlobalTypes;
  112.       BORDEBUG_SSTNAMES       : Result := soNames;
  113.       BORDEBUG_SSTBROWSE      : Result := soBrowse;
  114.    else                         raise Exception.Create('Unexpected SubSectionType!!');
  115.    end;
  116. end;
  117.  
  118. { TCustomBorDebugScanner }
  119.  
  120. constructor TCustomBorDebugScanner.Create(ABorDebug: TBorDebug);
  121. begin
  122.   inherited Create;
  123.   FBorDebug := ABorDebug;
  124. end;
  125.  
  126. procedure TCustomBorDebugScanner.ScanModuleSegment(const SubSection: TBorDebugSubSection;
  127.                                             Module: TBorDebugModule;
  128.                                             SegmentIndex: integer;
  129.                                       const Segment: TModuleSegment);
  130. begin
  131.  // Do nothing, by default...
  132. end;
  133.  
  134. procedure TCustomBorDebugScanner.ScanModule(const SubSection: TBorDebugSubSection; Module: TBorDebugModule; var KeepIt: boolean);
  135. var
  136.   i: integer;
  137.   Segment: TModuleSegment;
  138. begin
  139.   for i := 0 to Module.SegmentCount-1 do
  140.   begin
  141.     Segment := Module.Segments[i];
  142.     ScanModuleSegment(SubSection, Module, i, Segment);
  143.   end;
  144. end;
  145.  
  146. procedure TCustomBorDebugScanner.ScanSymbolTypeInfo(const SubSection: TBorDebugSubSection; SymbolInfo: TSymbolInfo; TypeInfo: TTypeInfo; var KeepIt: boolean);
  147. begin
  148.   // Do nothing
  149. end;
  150.  
  151. function TCustomBorDebugScanner.WantType(const BorDebugType: TBorDebugType): boolean;
  152. begin
  153.   // Always look at all types, by default...
  154.   Result := True;
  155. end;
  156.  
  157. function TCustomBorDebugScanner.WantFieldList(const SubSection: TBorDebugSubSection; SymbolInfo: TSymbolInfo; const BorDebugType: TBorDebugType): boolean;
  158. begin
  159.   // Always look at all field lists, by default...
  160.   Result := True;
  161. end;
  162.  
  163. function TCustomBorDebugScanner.WantTypeInfoForSymbol(SymbolInfo: TSymbolInfo; TypeIndex : TTypeIndex): boolean;
  164. begin
  165.   // Always look at the type of all symbols, by default...
  166.   Result := True;
  167. end;
  168.  
  169.  
  170. procedure TCustomBorDebugScanner.ScanSymbolTypeNode(const SubSection: TBorDebugSubSection; SymbolInfo: TSymbolInfo; BorDebugType: TBorDebugType);
  171. var
  172.   TypeInfo: TTypeInfo;
  173.   KeepIt: boolean;
  174. begin
  175.   if WantType(BorDebugType) then
  176.   begin
  177.     KeepIt := False;
  178.     TypeInfo := BorDebug.CreateTypeInfo(BorDebugType);
  179.     try
  180.       ScanSymbolTypeInfo(SubSection, SymbolInfo, TypeInfo, KeepIt);
  181.     finally
  182.       if not KeepIt then
  183.         TypeInfo.Free;
  184.     end;
  185.   end;
  186. end;
  187.  
  188. procedure TCustomBorDebugScanner.StartFieldListScan(const SubSection: TBorDebugSubSection; SymbolInfo: TSymbolInfo; BorDebugType: TBorDebugType);
  189. begin
  190.   // Do nothing
  191. end;
  192.  
  193. procedure TCustomBorDebugScanner.EndFieldListScan(const SubSection: TBorDebugSubSection; SymbolInfo: TSymbolInfo; BorDebugType: TBorDebugType);
  194. begin
  195.   // Do nothing
  196. end;
  197.  
  198. procedure TCustomBorDebugScanner.ScanSymbolTypeTree(const SubSection: TBorDebugSubSection; SymbolInfo: TSymbolInfo; TypeIndex: TTypeIndex);
  199. var
  200.   BorDebugType : TBorDebugType;
  201.   NextTypeIndex : TTypeIndex;
  202. begin
  203.   BorDebugType := BorDebug.TypeFromIndex[TypeIndex];
  204.   ScanSymbolTypeNode(SubSection, SymbolInfo, BorDebugType);
  205.   with BorDebugType do
  206.   begin
  207.     // special case!!
  208.     if (TypeKind = BORDEBUG_LF_FIELDLIST) and
  209.        WantFieldList(SubSection, SymbolInfo, BorDebugType) then
  210.     begin
  211.       StartFieldListScan(SubSection, SymbolInfo, BorDebugType);
  212.       // start the field list
  213.       BorDebugTypeStartFIELDLIST(BorDebug.Handle, TypeOffset);
  214.       while True do
  215.       begin
  216.         // next field
  217.         BorDebugTypeNextFIELDLIST(BorDebug.Handle, TypeKind, TypeOffset);
  218.  
  219.         // are we done?
  220.         if (TypeKind = 0) and (TypeOffset = 0) then
  221.           Break;
  222.  
  223.         // is this a continuation?
  224.         if  (TypeKind = BORDEBUG_LF_INDEX) then
  225.         begin
  226.           // get the continuation index and its offset
  227.           NextTypeIndex := BorDebugTypeINDEX(BorDebug.Handle, TypeOffset);
  228.           BorDebugTypeFromIndex(BorDebug.Handle, NextTypeIndex, TypeOffset, Length, TypeKind);
  229.  
  230.           // continue in the next field list
  231.           BorDebugTypeStartFIELDLIST(BorDebug.Handle, TypeOffset);
  232.           Continue;
  233.         end;
  234.  
  235.         // Call Tree here??
  236.         ScanSymbolTypeNode(SubSection, SymbolInfo, BorDebugType);
  237.       end;
  238.       EndFieldListScan(SubSection, SymbolInfo, BorDebugType);
  239.     end;
  240.   end;
  241. end;
  242.  
  243. procedure TCustomBorDebugScanner.ScanSymbolInfo(const SubSection: TBorDebugSubSection; SymbolInfo: TSymbolInfo; var KeepIt: boolean);
  244. var
  245.   TypeIndex : TTypeIndex;
  246. begin
  247.   if SymbolInfo.GetTypeIndex(TypeIndex) and WantTypeInfoForSymbol(SymbolInfo, TypeIndex) then
  248.     ScanSymbolTypeTree(SubSection, SymbolInfo, TypeIndex);
  249. end;
  250.  
  251. function TCustomBorDebugScanner.WantSymbol(const Symbol: TBorDebugSymbol): boolean;
  252. begin
  253.   // Always look at all symbols, by default...
  254.   Result := True;
  255. end;
  256.  
  257. procedure TCustomBorDebugScanner.ScanSymbols(const SubSection: TBorDebugSubSection);
  258. var
  259.   Symbol: TBorDebugSymbol;
  260.   SymbolInfo: TSymbolInfo;
  261.   KeepIt: boolean;
  262. begin
  263.   BorDebug.StartSymbols(SubSection);
  264.   while BorDebug.GetNextSymbol(Symbol) do
  265.     if WantSymbol(Symbol) then
  266.     begin
  267.       KeepIt := False;
  268.       SymbolInfo := BorDebug.CreateSymbolInfo(Symbol);
  269.       try
  270.         ScanSymbolInfo(SubSection, SymbolInfo, KeepIt);
  271.       finally
  272.         if not KeepIt then
  273.           SymbolInfo.Free;
  274.       end;
  275.     end;
  276. end;
  277.  
  278. procedure TCustomBorDebugScanner.ScanSrcModuleRange(const SubSection: TBorDebugSubSection;
  279.                                              SrcModule: TBorDebugSrcModule;
  280.                                              RangeIndex: integer;
  281.                                              RangeSegmentIndex: TSegmentIndex;
  282.                                              RangeStart: TSegmentOffset;
  283.                                              RangeEnd: TSegmentOffset);
  284. begin
  285.   // Do nothing, by default...
  286. end;
  287.  
  288. procedure TCustomBorDebugScanner.ScanLineNumberOffset(
  289.   LineNumber: TLineNumber;
  290.   LineOffset: TSegmentOffset);
  291. begin
  292.   // Do nothing, by default...
  293. end;
  294.  
  295. procedure TCustomBorDebugScanner.ScanSrcModuleSourceRange(
  296.   RangeIndex: integer;
  297.   Segment: TSegmentIndex;
  298.   Starts: TSegmentOffset;
  299.   Ends: TSegmentOffset;
  300.   LineNumberCount: TItemCount;
  301.   LineNumberOffsets: TLineNumberOffsets);
  302. var
  303.   i: integer;
  304. begin
  305.   FCurrentLineNumberOffsets := LineNumberOffsets;
  306.   for i := 0 to LineNumberCount-1 do
  307.     with LineNumberOffsets do
  308.       ScanLineNumberOffset(LineNumbers^[i], LineOffsets^[i]);
  309. end;
  310.  
  311. procedure TCustomBorDebugScanner.ScanSrcModuleSource(const SubSection: TBorDebugSubSection;
  312.                                               SrcModule: TBorDebugSrcModule;
  313.                                               SourceIndex: integer;
  314.                                               SourceOffset: TFileOffset;
  315.                                               NameIndex: TNameIndex;
  316.                                               RangeCount: TItemCount;
  317.                                               SourceFileEntry: TSourceFileEntry);
  318. var
  319.   i: integer;
  320. begin
  321.   FCurrentSourceFileEntry := SourceFileEntry;
  322.   for i := 0 to RangeCount-1 do
  323.     with SourceFileEntry do
  324.     begin
  325.       ScanSrcModuleSourceRange(i, RangeSegments^[i],
  326.                                   RangeSegmentStarts^[i],
  327.                                   RangeSegmentEnds^[i],
  328.                                   LineNumberCounts^[i],
  329.                                   TLineNumberOffsets(LineNumerOffsetList.List^[i]));
  330.    end;
  331. end;
  332.  
  333. procedure TCustomBorDebugScanner.ScanSrcModule(const SubSection: TBorDebugSubSection; SrcModule: TBorDebugSrcModule; var KeepIt: boolean);
  334. var
  335.   i: integer;
  336. begin
  337.   if soSrcModuleRanges in ScanningOptions then
  338.     with SrcModule do
  339.       for i := 0 to RangeCount-1 do
  340.         ScanSrcModuleRange(SubSection, SrcModule, i, RangeSegments^[i],
  341.                                                      RangeSegmentStarts^[i],
  342.                                                      RangeSegmentEnds^[i]);
  343.   if soSrcModuleFiles in ScanningOptions then
  344.     with SrcModule do
  345.       for i := 0 to SrcModule.SourceCount-1 do
  346.         ScanSrcModuleSource(SubSection, SrcModule, i, SourceOffsets^[i],
  347.                                                       NameIndices^[i],
  348.                                                       RangeCounts^[i],
  349.                                      TSourceFileEntry(SourceFileList.List^[i]));
  350. end;
  351.  
  352. procedure TCustomBorDebugScanner.ScanSubSection(SubSectionIndex: integer; const SubSection: TBorDebugSubSection);
  353. var
  354.   KeepIt: boolean;
  355. begin
  356.   FCurrentSubSection := @SubSection;
  357.   if SubsectionTypeToScanningOption(SubSection.SubsectionType) in ScanningOptions then
  358.   begin
  359.     KeepIt := False;
  360.     case SubSection.SubsectionType of
  361.       BORDEBUG_SSTMODULE      :
  362.         begin
  363.           FCurrentModule := BorDebug.CreateModule(SubSection);
  364.           try
  365.             ScanModule(SubSection, FCurrentModule, KeepIt);
  366.           finally
  367.             if not KeepIt then
  368.               FreeAndNil(FCurrentModule);
  369.           end;
  370.         end;
  371.       BORDEBUG_SSTGLOBALSYM,
  372.       BORDEBUG_SSTGLOBALPUB,
  373.       BORDEBUG_SSTALIGNSYM    : ScanSymbols(SubSection);
  374.       BORDEBUG_SSTSRCMODULE   :
  375.         begin
  376.           FCurrentSrcModule := BorDebug.CreateSrcModule(SubSection);
  377.           try
  378.             ScanSrcModule(SubSection, FCurrentSrcModule, KeepIt);
  379.           finally
  380.             if not KeepIt then
  381.               FreeAndNil(FCurrentSrcModule);
  382.           end;
  383.         end;
  384.       BORDEBUG_SSTGLOBALTYPES : ;
  385.       BORDEBUG_SSTNAMES       : ;
  386.       BORDEBUG_SSTBROWSE      : ;
  387.     end;
  388.   end;
  389. end;
  390.  
  391. procedure TCustomBorDebugScanner.ScanSubsections;
  392. var
  393.   i : integer;
  394. begin
  395.   for i := 0 to BorDebug.SubSectionCount-1 do
  396.     ScanSubSection(i, BorDebug.SubSections[i]);
  397. end;
  398.  
  399. procedure TCustomBorDebugScanner.Scan(ScanningOptions: TScanningOptions);
  400. begin
  401.   FScanningOptions := ScanningOptions;
  402.   BorDebug.Active := True;
  403.   ScanSubsections;
  404. end;
  405.  
  406. { TLineNumberScanner }
  407.  
  408. procedure TLineNumberScanner.ScanLineNumberOffset(LineNumber: TLineNumber; LineOffset: TSegmentOffset);
  409. begin
  410.   case FTask of
  411.     ltMatchAddress :
  412.       begin
  413.         if (LineOffset <= FAddress) and (LineOffset > FBestMatch) then
  414.         begin
  415.           FBestMatch := LineOffset;
  416.           FFoundMatch := True;
  417.           FLinenumber := Linenumber;
  418.           // TODO: Improvement; limit to source modules that have the right range!
  419.           FUnitName := FCurrentSourceFileEntry.Name;
  420.         end;
  421.       end;
  422.     stMatchUnitLinenr:
  423.       ; // Not implemented yet...
  424.   end;
  425. end;
  426.  
  427. function TLineNumberScanner.FindUnitnameLinenumber(Address: TSegmentOffset;
  428.   out Unitname: string; out Linenumber: TLinenumber): boolean;
  429. begin
  430.   FTask := ltMatchAddress;
  431.   FAddress := Address;
  432.   FFoundMatch := false;
  433.   FBestMatch := 0;
  434.   Scan([soSrcModule, soSrcModuleFiles]);
  435.   Result := FFoundMatch;
  436.   if Result then
  437.   begin
  438.     Unitname := FUnitname;
  439.     Linenumber := FLinenumber;
  440.   end;
  441. end;
  442.  
  443. end.
  444.